﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Windows;
using System.Windows.Input;
using Xceed.Silverlight.Data;
using Xceed.Silverlight.DataGrid.Utils;

namespace Xceed.Silverlight.DataGrid
{
  #region Metadata

  [TemplateVisualState( GroupName = "CommonStates", Name = "Normal" )]
  [TemplateVisualState( GroupName = "CommonStates", Name = "Selected" )]
  [TemplateVisualState( GroupName = "CommonStates", Name = "MouseOver" )]
  [TemplateVisualState( GroupName = "CommonStates", Name = "MouseOverSelected" )]

  [TemplateVisualState( GroupName = "CurrentStates", Name = "Current" )]
  [TemplateVisualState( GroupName = "CurrentStates", Name = "NotCurrent" )]

  [StyleTypedProperty( Property = "CellStyle", StyleTargetType = typeof( Cell ) )]

  [TemplatePart( Name = "CellsHost", Type = typeof( ColumnElementsHost ) )]

  #endregion //Metadata

  public class Row : ControlBase, IDataGridElement, IColumnElementHost, INotifyPropertyChanged
  {
    internal static readonly XceedRoutedEvent OnMouseEnterRowEvent = new XceedRoutedEvent();
    internal static readonly XceedRoutedEvent OnMouseLeaveRowEvent = new XceedRoutedEvent();
    internal static readonly XceedRoutedEvent RowMouseLeftButtonDownEvent = new XceedRoutedEvent();
    internal static readonly XceedRoutedEvent RowMouseLeftButtonUpEvent = new XceedRoutedEvent();
    internal static readonly XceedRoutedEvent OnRowCellStyleChangedEvent = new XceedRoutedEvent();

    internal static readonly string CurrentStateCurrent = "Current";
    internal static readonly string CurrentStateNotCurrent = "NotCurrent";

    public Row()
    {
      this.DefaultStyleKey = typeof( Row );
      this.DataContext = null;
      this.VisualStateHelper = new VisualStateHelper( this );

      m_propertyChangedHelper = new NotifyPropertyChangedHelper( this, this.RaisePropertyChangedEvent );
    }

    #region CellStyle Property

    public static readonly DependencyProperty CellStyleProperty = DependencyProperty.Register(
      "CellStyle",
      typeof( Style ),
      typeof( Row ),
      new PropertyMetadata( null, Row.OnCellStyleChanged ) );

    public Style CellStyle
    {
      get
      {
        return ( Style )this.GetValue( Row.CellStyleProperty );
      }
      set
      {
        this.SetValue( Row.CellStyleProperty, value );
      }
    }


    private static void OnCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var row = ( Row )sender;
      row.EventManager.RaiseEvent( Row.OnRowCellStyleChangedEvent, new XceedRoutedEventArgs( row ) );
    }

    #endregion

    internal UIElement Visual
    {
      get
      {
        return this;
      }
    }

    internal ColumnElementsHost CellsHost
    {
      get
      {
        return m_cellsHost;
      }
    }

    internal IEnumerable<ColumnElementWrapper> Elements
    {
      get
      {
        return m_cellsHost.Elements;
      }
    }

    internal IEnumerable<ColumnElementWrapper> RenderedElements
    {
      get
      {
        return m_cellsHost.Elements
          .Where( ( w ) => !w.ColumnElement.ParentColumnContainer.IsRecycled );
      }
    }

    internal IEnumerable<Cell> RenderedCells
    {
      get
      {
        return this.RenderedElements
          .Select( ( w ) => ( Cell )w.ColumnElement );
      }
    }

    internal double CellsOffset
    {
      get
      {
        return m_cellsHost.CellsIndent;
      }
      set
      {
        m_cellsHost.CellsIndent = value;
      }
    }

    #region VisualStateHelper Property

    internal VisualStateHelper VisualStateHelper
    {
      get;
      private set;
    }

    #endregion VisualStateHelper Property

    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      ColumnElementsHost cellsHost = this.GetTemplateChild( "CellsHost" ) as ColumnElementsHost;

      if( cellsHost == null )
      {
        cellsHost = new ColumnElementsHost();
      }

      m_cellsHost.TransfertCells( cellsHost );
      m_cellsHost = cellsHost;

      this.VisualStateHelper.ApplyVisualStates();
    }

    protected override void OnMouseEnter( MouseEventArgs e )
    {
      base.OnMouseEnter( e );

      this.EventManager.RaiseEvent( Row.OnMouseEnterRowEvent, new XceedRoutedEventArgs( this ) );
    }

    protected override void OnMouseLeave( MouseEventArgs e )
    {
      base.OnMouseLeave( e );

      this.EventManager.RaiseEvent( Row.OnMouseLeaveRowEvent, new XceedRoutedEventArgs( this ) );
    }

    protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e )
    {
      XceedEventUtils.RaiseMouseButtonEvent( this, e, Row.RowMouseLeftButtonDownEvent );
    }

    protected override void OnMouseLeftButtonUp( MouseButtonEventArgs e )
    {
      XceedEventUtils.RaiseMouseButtonEvent( this, e, Row.RowMouseLeftButtonUpEvent );
    }

    internal void SetCurrentState( bool isCurrent, bool useTransitions )
    {
      string state = ( isCurrent ) ? Row.CurrentStateCurrent : Row.CurrentStateNotCurrent;
      this.VisualStateHelper.GoToCurrentState( state, useTransitions );
    }

    internal void SetRowStyle( Style style )
    {
      if( style != this.Style )
      {
        if( style == null )
        {
          this.ClearValue( Row.StyleProperty );
        }
        else
        {
          this.Style = style;
        }
      }
    }

    internal virtual void InvalidateColumnArrange()
    {
      m_cellsHost.InvalidateColumnArrange();
    }

    internal virtual void InvalidateColumnMeasure()
    {
      m_cellsHost.InvalidateColumnMeasure();
    }

    internal virtual void AddColumnElement( ColumnElementWrapper element )
    {
      m_cellsHost.AddColumnElement( element );
    }

    internal virtual void RemoveColumnElement( ColumnElementWrapper element )
    {
      m_cellsHost.RemoveColumnElement( element );
    }

    internal virtual void SetElementPosition( ColumnElementWrapper element, ColumnPosition position )
    {
      m_cellsHost.SetElementPosition( element, position );
    }

    #region IColumnContainer interface

    IEnumerable<ColumnElementWrapper> IColumnElementHost.Elements
    {
      get
      {
        return this.Elements;
      }
    }

    void IColumnElementHost.InvalidateColumnArrange()
    {
      this.InvalidateColumnArrange();
    }

    void IColumnElementHost.InvalidateColumnMeasure()
    {
      this.InvalidateColumnMeasure();
    }

    void IColumnElementHost.AddColumnElement( ColumnElementWrapper element )
    {
      this.AddColumnElement( element );
    }

    void IColumnElementHost.RemoveColumnElement( ColumnElementWrapper element )
    {
      this.RemoveColumnElement( element );
    }

    void IColumnElementHost.SetElementPosition( ColumnElementWrapper element, ColumnPosition position )
    {
      this.SetElementPosition( element, position );
    }

    #endregion IColumnContainer interface

    #region IDataGridElement

    UIElement IDataGridElement.Visual
    {
      get
      {
        return this.Visual;
      }
    }

    DataPath IDataGridElement.Path
    {
      get
      {
        return this.Path;
      }
    }

    internal DataPath Path
    {
      get
      {
        return m_path;
      }
    }

    void IDataGridElement.SetDataPath( DataPath path )
    {
      this.SetDataPath( path );
    }

    internal virtual void SetDataPath( DataPath path )
    {
      if( path == null )
        throw new ArgumentNullException( "path" );

      m_path = path;
    }
    #endregion

    #region IVisitorElement Members

    void IVisitorElement.Accept( IVisitor visitor )
    {
      this.Accept( visitor );
    }

    internal virtual void Accept( IVisitor visitor )
    {
      visitor.Visit( this );
    }

    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged( string propertyName )
    {
      m_propertyChangedHelper.RaisePropertyChanged( propertyName );
    }

    protected void RaisePropertyChanged<TMember>( Expression<Func<TMember>> expression )
    {
      m_propertyChangedHelper.RaisePropertyChanged( expression );
    }

    private void RaisePropertyChangedEvent( string propertyName )
    {
      if( this.PropertyChanged != null )
      {
        this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
      }
    }

    private readonly NotifyPropertyChangedHelper m_propertyChangedHelper;

    #endregion



    private DataPath m_path;
    private ColumnElementsHost m_cellsHost = new ColumnElementsHost();
  }
}
